//01函子
// class Container {
//     constructor(v) {
//         this._v = v
//     }
//     map(fn) {
//         return new Container(fn(this._v))
//     }
// }

// let r = new Container(5)
//     .map(x => x + 1)
//     .map(x => x * x)
// console.log(r)

//02优化
class Container {
  static of(v) {
    return new Container(v);
  }
  constructor(v) {
    this._v = v;
  }
  map(fn) {
    return Container.of(fn(this._v));
  }
}
let r = Container.of(4)
  .map((x) => x + 2)
  .map((x) => x * x);
console.log(r);

// 演示函子传递null undefined 的问题
// Container.of(null).map(x => x.toUpperCase())

//03mayge函子=>解决函子传递null undefined
class MayBe {
  static of(v) {
    return new MayBe(v);
  }
  constructor(v) {
    this._v = v;
  }
  map(fn) {
    return this.isNothing() ? MayBe.of(null) : MayBe.of(fn(this._v));
  }
  isNothing() {
    return this._v === null || this._v === undefined;
  }
}
let r1 = MayBe.of(null).map((x) => x.toUpperCase());
// 问题 我们不能确定到底是哪一步传递了null
// let r1 = MayBe.of('hello world')
//     .map(x => x.toUpperCase())
//     .map(null)
//     .map(x => x.spilt(' '))
console.log(r1);

// 04Either 函子  可以处理异常 并记录错误信息
class Left {
  static of(v) {
    return new Left(v);
  }
  constructor(v) {
    this._v = v;
  }
  map(fn) {
    return this;
  }
}
class Right {
  static of(v) {
    return new Right(v);
  }
  constructor(v) {
    this._v = v;
  }
  map(fn) {
    return Right.of(fn(this._v));
  }
}
// let r2 = Right.of(12)
//     .map(x => x + 2)
// let r3 = Left.of(12)
//     .map(x => x + 2)
// console.log(r2, r3)
function parseJOSN(str) {
  try {
    return Right.of(JSON.parse(str));
  } catch (e) {
    return Left.of({ error: e.message });
  }
}
// let r4 = parseJOSN('{name:caozy}')
let r4 = parseJOSN('{"name":"caozy"}');
console.log(r4);

const { first } = require("lodash");
/*05IO 函子
        -函子中的_v是一个函数 这里是把函数作为值处理
        -把不纯的操作交给调用者处理
        -io函子可以不纯的动作保存到_v中，延迟执行这个不纯的操作，包装当前的纯操作
*/
const fp = require("lodash/fp");
class IO {
  static of(v) {
    return new IO(function () {
      return v;
    });
  }
  constructor(fn) {
    this._v = fn;
  }
  map(fn) {
    return new IO(fp.flowRight(fn, this._v));
  }
  join() {
    return this._v();
  }
  flatMap(fn) {
    return this.map(fn).join();
  }
}
// 测试
let r5 = IO.of(process).map((p) => p.execPath);
console.log(r5._v());

const fs = require("fs");
let readFile = function (fileName) {
  return new IO(function () {
    return fs.readFileSync(fileName, "utf-8");
  });
};
let print = function (x) {
  return new IO(function () {
    return x;
  });
};
let cat = fp.flowRight(print, readFile);
// console.log(cat("package.json")._v()._v());

// 06 IO Monad 解决函子嵌套的问题
let r6 = readFile("package.json").flatMap(print).join();
console.log(r6);

// 07 Pointed 函子  有of方法的函子
